package com.huirui.server.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.huirui.server.constant.RedisConstant;
import com.huirui.server.constant.StatusConstant;
import com.huirui.server.constant.UserConstant;
import com.huirui.server.context.UserContext;
import com.huirui.server.exception.VerificationCodeErrorException;
import com.huirui.server.generator.NickNameGenerator;
import com.huirui.server.mapper.UserMapper;
import com.huirui.server.pojo.dto.UserSettingDto;
import com.huirui.server.pojo.dto.VerificationCodeLoginDTO;
import com.huirui.server.pojo.dto.WeChatSessionDto;
import com.huirui.server.pojo.entity.User;
import com.huirui.server.pojo.result.PageResult;
import com.huirui.server.pojo.vo.UserBriefInfoVo;
import com.huirui.server.pojo.vo.UserSettingVo;
import com.huirui.server.pojo.vo.UserVo;
import com.huirui.server.properties.WeChatProperties;
import com.huirui.server.service.UserService;
import com.huirui.server.util.JwtUtil;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * @author yujun
 * @description 针对表【t_user(用户表)】的数据库操作Service实现
 * @createDate 2025-09-14 10:48:11
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate redisTemplate;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private WeChatProperties weChatProperties;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private OkHttpClient okHttpClient;

    @Override
    public String getVerificationCode(String phone) {
        SecureRandom random = new SecureRandom();
        char[] digits = new char[6];
        char[] numbers = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        for (int i = 0; i < 6; i++) {
            digits[i] = numbers[random.nextInt(10)];
        }
        String code = new String(digits);
        log.info("验证码:{}", code);
        redisTemplate
                .opsForValue()
                .set(RedisConstant.CODE_PREFIX + phone, code, RedisConstant.CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
        return code;
    }

    @Override
    public String loginByVerificationCode(VerificationCodeLoginDTO loginDTO) {
        String phone = loginDTO.getPhone();
        String code = loginDTO.getCode();
        String redisCode = redisTemplate.opsForValue().get(RedisConstant.CODE_PREFIX + phone);
        if (!code.equals(redisCode)) {
            throw new VerificationCodeErrorException("验证码错误");
        }
        User user = lambdaQuery().eq(User::getPhone, phone).one();
        if (user == null) {
            // 插入新用户
            String nickName = NickNameGenerator.generateUsername();
            user = new User();
            user.setNickname(nickName);
            user.setAvatarUrl(UserConstant.DEFAULT_AVATAR);
            user.setPhone(phone);
            user.setRegisterTime(LocalDateTime.now());
            user.setLastLoginTime(LocalDateTime.now());
            user.setLoginCount(1);
            user.setStatus(StatusConstant.ENABLE);
            save(user);
        } else {
            user.setLastLoginTime(LocalDateTime.now());
            user.setLoginCount(user.getLoginCount() + 1);
            lambdaUpdate().update(user);
        }
        Long userId = user.getId();
        return jwtUtil.createToken(userId);
    }


    @Override
    public UserBriefInfoVo getUserBriefInfo() {
        Long userId = UserContext.getId();
        User user = lambdaQuery()
                .select(User::getNickname, User::getAvatarUrl)
                .eq(User::getId, userId)
                .one();
        return UserBriefInfoVo
                .builder()
                .userName(user.getNickname())
                .avatar(user.getAvatarUrl())
                .build();
    }

    @Override
    public String loginByWeChatOpenid(String code) {
        // 构建请求URL
        String url = WeChatProperties.WX_LOGIN_URL + "?appid=" + weChatProperties.getAppid() + "&secret=" + weChatProperties.getSecret() +
                "&js_code=" + code + "&grant_type=authorization_code";
        String response = restTemplate.getForObject(url, String.class);
        Gson gson = new Gson();
        WeChatSessionDto sessionDto = gson.fromJson(response, WeChatSessionDto.class);
        String session_key = sessionDto.getSession_key();
        String openId = sessionDto.getOpenid();
        User user = lambdaQuery().eq(User::getOpenid, openId).one();
        if (user == null) {
            // 插入新用户
            String nickName = NickNameGenerator.generateUsername();
            user = new User();
            user.setNickname(nickName);
            user.setAvatarUrl(UserConstant.DEFAULT_AVATAR);
            user.setOpenid(openId);
            user.setRegisterTime(LocalDateTime.now());
            user.setLastLoginTime(LocalDateTime.now());
            user.setLoginCount(1);
            user.setStatus(StatusConstant.ENABLE);
            save(user);
        }
        Long userId = user.getId();
        return jwtUtil.createToken(userId);
    }

    @Override
    public UserSettingVo getUserSettingInfo() {
        Long userId = UserContext.getId();
        User user = lambdaQuery()
                .select(User::getPhone, User::getAvatarUrl, User::getPhone, User::getNickname, User::getBirthday)
                .eq(User::getId, userId)
                .one();
        UserSettingVo userSettingVo = new UserSettingVo();
        userSettingVo.setNickName(user.getNickname());
        userSettingVo.setBirthday(user.getBirthday());
        userSettingVo.setPhoneNumber(user.getPhone());
        userSettingVo.setImageUrl(user.getAvatarUrl());
        return userSettingVo;
    }

    @Override
    public void updateUserInformation(UserSettingDto userSettingDto) {

        lambdaUpdate()
                .set(userSettingDto.getBirthday() != null, User::getBirthday, userSettingDto.getBirthday())
                .set(userSettingDto.getNickName() != null, User::getNickname, userSettingDto.getNickName())
                .set(userSettingDto.getImageUrl() != null, User::getAvatarUrl, userSettingDto.getImageUrl())
                .set(userSettingDto.getPhoneNumber() != null, User::getPhone, userSettingDto.getPhoneNumber())
                .eq(User::getId, UserContext.getId())
                .update();
    }

    @Override
    public PageResult<UserVo> listByCondition(
            String userName,
            Long userId,
            String phoneNumber,
            LocalDate registrationStartDate,
            LocalDate registrationEndDate,
            BigDecimal minimumConsumptionAmount,
            BigDecimal maximumConsumptionAmount,
            Long page,
            Long pageSize
    ) {
        IPage<User> iPage = new Page<>(page, pageSize);
        LambdaQueryChainWrapper<User> queryWrapper = lambdaQuery()
                .like(StringUtils.isNotBlank(userName), User::getNickname, userName)
                .eq(ObjectUtils.isNotEmpty(userId), User::getId, userId)
                .eq(StringUtils.isNotBlank(phoneNumber), User::getPhone, phoneNumber)
                .ge(ObjectUtils.isNotEmpty(minimumConsumptionAmount), User::getConsumptionAmount, minimumConsumptionAmount)
                .le(ObjectUtils.isNotEmpty(maximumConsumptionAmount), User::getConsumptionAmount, maximumConsumptionAmount);
        if (registrationStartDate != null) {
            queryWrapper.ge(User::getRegisterTime, registrationStartDate.atStartOfDay()); // 00:00:00
        }
        if (registrationEndDate != null) {
            queryWrapper.le(User::getRegisterTime, registrationEndDate.atTime(LocalTime.MAX)); // 23:59:59.999999999
        }
        queryWrapper
                .orderByDesc(User::getRegisterTime)
                .page(iPage);
        PageResult<UserVo> res = new PageResult<>();
        res.setPages(iPage.getPages());
        res.setTotal(iPage.getTotal());
        res.setSize(iPage.getSize());
        res.setCurrent(iPage.getCurrent());
        List<UserVo> userVoList = iPage
                .getRecords()
                .stream()
                .map(user -> UserVo
                        .builder()
                        .userAvatar(user.getAvatarUrl())
                        .userId(user.getId())
                        .userName(user.getNickname())
                        .phoneNumber(user.getPhone())
                        .balance(user.getBalance())
                        .consumptionAmount(user.getConsumptionAmount())
                        .registrationDate(user.getRegisterTime())
                        .lastLoginDate(user.getLastLoginTime())
                        .build()
                )
                .toList();
        res.setRecords(userVoList);
        return res;
    }

    @SneakyThrows
    @Override
    public String loginQuickly(String code) {
        HttpUrl url = HttpUrl
                .parse("https://api.weixin.qq.com/cgi-bin/token")
                .newBuilder()
                .addQueryParameter("grant_type", "client_credential")
                .addQueryParameter("appid", weChatProperties.getAppid())
                .addQueryParameter("secret", weChatProperties.getSecret())
                .build();
        Request request = new Request
                .Builder()
                .url(url)
                .build();
        Response response1 = okHttpClient.newCall(request).execute();
        JsonObject jsonObject = JsonParser.parseString(response1.body().string()).getAsJsonObject();
        String accessToken = jsonObject.get("access_token").getAsString();
        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        String jsonBody = "{\"code\": \"" + code + "\"}"; // 拼接 JSON（或用工具类序列化）
        RequestBody requestBody = RequestBody.create(jsonBody, JSON);
        url = HttpUrl
                .parse("https://api.weixin.qq.com/wxa/business/getuserphonenumber")
                .newBuilder()
                .addQueryParameter("access_token", accessToken)
                .build();
        request = new Request
                .Builder()
                .url(url)
                .post(requestBody) // 传入 JSON 请求体
                .header("Content-Type", "application/json") // 显式指定 JSON 格式
                .build();
        Response response2 = okHttpClient.newCall(request).execute();
        JsonElement jsonElement = JsonParser.parseString(response2.body().string());
        JsonObject rootObject = jsonElement.getAsJsonObject();
        JsonObject phoneInfoObject = rootObject.getAsJsonObject("phone_info"); // 获取phone_info对象
        String phoneNumber = phoneInfoObject.get("phoneNumber").getAsString(); // 提取phoneNumber
        log.info(phoneNumber);
        // 查询是否为新用户
        User user = lambdaQuery()
                .eq(User::getPhone, phoneNumber)
                .one();
        if (user == null) {
            user = new User();
            user.setNickname(NickNameGenerator.generateUsername());
            user.setAvatarUrl(UserConstant.DEFAULT_AVATAR);
            user.setPhone(phoneNumber);
            user.setConsumptionAmount(BigDecimal.ZERO);
            user.setRegisterTime(LocalDateTime.now());
            user.setLastLoginTime(LocalDateTime.now());
            user.setBalance(BigDecimal.ZERO);
            user.setStatus(StatusConstant.ENABLE);
            user.setLoginCount(1);
            user.setGender(-1);
            save(user);
        } else {
            user.setLoginCount(user.getLoginCount() + 1);
            user.setLastLoginTime(LocalDateTime.now());
        }
        response1.close();
        response2.close();
        return jwtUtil.createToken(user.getId());
    }
}




